﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace Brain.Editor
{
    /// <summary>
    /// Holds a reference to all content used by a (single) Scene
    /// </summary>
    public class SceneContent : IBrainSerialiable
    {
        /// <summary>
        /// All the Files this Scene Content is currently holding.
        /// If everything is running like planned, all those files are 
        /// on memory ready to use
        /// </summary>
        public List<SceneContentFile> Files { get; protected set; }

        /// <summary>
        /// If the SceneContent should serialize itself.
        /// Just to hold the IBrainSerialiable interface.
        /// Changing this value might end in an exception.
        /// </summary>
        public bool ShouldSerialize { get; set; }

        /// <summary>
        /// The Data thi Scene Content will use to serialize itself to.
        /// </summary>
        public SerializationData Data { get; set; }

        /// <summary>
        /// Initializes an instance of SceneContent, loading
        /// the data from an XNA content project
        /// </summary>
        /// <param name="xnaContentProjectStream">A Stream to load from an XNA Content Project file</param>
        public SceneContent(Stream xnaContentProjectStream)
            :this()
        {
            ReadXNAContentProject(xnaContentProjectStream);
        }
        /// <summary>
        /// Initializes an instance of SceneContent
        /// </summary>
        public SceneContent()
        {
            Files = new List<SceneContentFile>();
            ShouldSerialize = true;
        }

        /// <summary>
        /// Reads an XNA Content Project
        /// </summary>
        /// <param name="str"></param>
        private void ReadXNAContentProject(Stream str)
        {
#if !SILVERLIGHT
            XmlReader reader = XmlReader.Create(str);

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.Name == "Project")
                    {
                        while (reader.Read())
                        {
                            if (reader.Name == "ItemGroup")
                            {
                                while (reader.Read())
                                {
                                    if (reader.Name == "Compile")
                                    {
                                        SceneContentFile file = new SceneContentFile();
                                        file.Project = this;
                                        string s = reader.GetAttribute("Include");
                                        file.RelativePath = s;
                                        file.FileExtension = Path.GetExtension(s);
                                        while (reader.Read() && reader.NodeType != XmlNodeType.EndElement)
                                        {
                                            if (reader.NodeType != XmlNodeType.Whitespace)
                                            {
                                                string att = reader.Name;
                                                string value = reader.ReadElementContentAsString();

                                                string lower = att.ToLower();
                                                if (lower == "name")
                                                {
                                                    file.Name = value;
                                                }
                                                else if (lower == "importer")
                                                {
                                                    file.Importer = value;
                                                }
                                                else if (lower == "processor")
                                                {
                                                    file.Processor = value;
                                                }
                                                else if (lower.StartsWith("processorparameters_"))
                                                {
                                                    if (file.ProcessorParameters == null)
                                                    {
                                                        file.ProcessorParameters = new List<NameValue>();
                                                    }
                                                    file.ProcessorParameters.Add(
                                                        new NameValue(att.Remove(0, 20),
                                                            value));
                                                }
                                                else if (lower.StartsWith("importerparameters_"))
                                                {
                                                    if (file.ImporterParameters == null)
                                                    {
                                                        file.ImporterParameters = new List<NameValue>();
                                                    }
                                                    file.ImporterParameters.Add(
                                                        new NameValue(att.Remove(0, 20),
                                                            value));
                                                }
                                            }
                                        }
                                        Files.Add(file);
                                    }
                                }
                            }
                        }
                    }
                }
            }
#endif
        }

        public void SerializeData(DefaultSerializationManager manager)
        {
            Data = new SerializationData();

            Data.AddData("ContentProject.Files", Files.Count);
            for (int i = 0; i < Files.Count; i++)
            {
                SceneContentFile file = Files[i];

                Data.AddData("ContentProjectFile.FileExtension" + i, file.FileExtension);
                Data.AddData("ContentProjectFile.Importer" + i, file.Importer);

                if (file.ImporterParameters != null)
                {
                    Data.AddData("ContentProjectFile.ImporterParameters" + i, file.ImporterParameters.Count);
                    for (int x = 0; x < file.ImporterParameters.Count; x++)
                    {
                        NameValue value = file.ImporterParameters[x];
                        Data.AddData("ContentProjectFile.ImporterParameter.Name" + i + ":" + x, value.Name);
                        Data.AddData("ContentProjectFile.ImporterParameter.Value" + i + ":" + x, value.Value);
                    }
                }

                Data.AddData("ContentProjectFile.Name" + i, file.Name);
                Data.AddData("ContentProjectFile.ProcessedPath" + i, file.ProcessedPath);
                Data.AddData("ContentProjectFile.Processor" + i, file.Processor);

                if (file.ProcessorParameters != null)
                {
                    Data.AddData("ContentProjectFile.ProcessorParameters" + i, file.ImporterParameters.Count);
                    for (int x = 0; x < file.ProcessorParameters.Count; x++)
                    {
                        NameValue value = file.ProcessorParameters[x];
                        Data.AddData("ContentProjectFile.ProcessorParameter.Name" + i + ":" + x, value.Name);
                        Data.AddData("ContentProjectFile.ProcessorParameter.Value" + i + ":" + x, value.Value);
                    }
                }
                Data.AddData("ContentProjectFile.RelativePath" + i, file.RelativePath);
            }
        }

        public void DeserializeData(DefaultSerializationManager manager, SerializationData NewData)
        {
            this.Data = NewData;

            int files = Data.GetData<int>("ContentProject.Files");
            for (int i = 0; i < files; i++)
            {
                SceneContentFile file = new SceneContentFile();
                file.Project = this;

                file.FileExtension = Data.GetData<string>("ContentProjectFile.FileExtension" + i);
                file.Importer = Data.GetData<string>("ContentProjectFile.Importer" + i);

                int importer = Data.GetData<int>("ContentProjectFile.ImporterParameters" + i);
                if (importer > 0)
                {
                    file.ImporterParameters = new List<NameValue>();
                    for (int x = 0; x < importer; x++)
                    {
                        string name = Data.GetData<string>("ContentProjectFile.ImporterParameter.Name" + i + ":" + x);
                        string valueS = Data.GetData<string>("ContentProjectFile.ImporterParameter.Value" + i + ":" + x);
                        NameValue value = new NameValue(name, valueS);
                        file.ImporterParameters.Add(value);
                    }
                }

                file.Name = Data.GetData<string>("ContentProjectFile.Name" + i);
                file.ProcessedPath = Data.GetData<string>("ContentProjectFile.ProcessedPath" + i);
                file.Processor = Data.GetData<string>("ContentProjectFile.Processor" + i);

                int processors = Data.GetData<int>("ContentProjectFile.ProcessorParameters" + i);
                if (processors > 0)
                {
                    file.ProcessorParameters = new List<NameValue>();
                    for (int x = 0; x < processors; x++)
                    {
                        string name = Data.GetData<string>("ContentProjectFile.ProcessorParameter.Name" + i + ":" + x);
                        string valueS = Data.GetData<string>("ContentProjectFile.ProcessorParameter.Value" + i + ":" + x);
                        NameValue value = new NameValue(name, valueS);
                        file.ProcessorParameters.Add(value);
                    }
                }
                file.RelativePath = Data.GetData<string>("ContentProjectFile.RelativePath" + i);

                this.Files.Add(file);
            }
        }

        public void DeserializedAll()
        {
        }
    }
}
